package com.example.starter.redisson.handler;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.example.starter.redisson.anntation.RedissonLock;
import com.example.starter.redisson.configure.RedissonProperties;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

/**
 * @author 王令
 * @since 2022/11/23 15:05
 */
@RequiredArgsConstructor
public class SpELKeyGenerator implements KeyGenerator {

    private static final ExpressionParser parser = new SpelExpressionParser();

    private final RedissonProperties properties;

    @Override
    public String generate(JoinPoint point, RedissonLock lock) {
        String lockKey = properties.getLockPrefix();
        if (StrUtil.isBlank(lock.name())) {
            lockKey += point.getSignature().getName();
        } else {
            lockKey += lock.name();
        }
        StandardEvaluationContext context = getElContext(point);
        return lockKey + StrPool.COLON + parser.parseExpression(lock.key()).getValue(context, String.class);
    }

    private StandardEvaluationContext getElContext(JoinPoint joinPoint) {
        StandardEvaluationContext context = new StandardEvaluationContext();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] parameterNames = signature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        if (ObjUtil.isNotEmpty(parameterNames)) {
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], args[i]);
            }
        }
        return context;
    }

}
